using Glpt.Data;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Text;

namespace Glpt.Task
{
    /// <summary>
    /// 开放式基金文件流类
    /// </summary>
    public class OFDataReader : IDataReader
    {
        private StreamReader stream;
        private Dictionary<string, int> columnsByName = new Dictionary<string, int>();
        private Dictionary<int, string> columnsByOrdinal = new Dictionary<int, string>();
        private Dictionary<string, string> colnames_ext = new Dictionary<string, string>();//附加列
        private int Cols_ext = 0; //附加列的个数
        private int Col_rowIndex = -1;//自增字段列序号
        private Dictionary<int, string> colnames_rowindex = new Dictionary<int, string>();
        private string[] currentRow;
        private bool _isClosed = true;
        private int rowcount = 0;
        private int irowIndex = 0;
        private int iLineColCount = 10;
        private int iLineRowCount = 10;
        DictColInfo[] colnames = new DictColInfo[0];
        private Encoding encoding = DataFuns.DefaultEncoding;
        private string dict_type = "of";
        private static DataTable _DictCache = null;//字典表
        private DataTable TableDictCache
        {
            get
            {
                if (_DictCache == null)
                {
                    string sql_dict = "SELECT * FROM TB_DICT_OF";
                    _DictCache = new BaseInterFace().ExecSelect(sql_dict);
                }
                return _DictCache;
            }
        }
        /// <summary>
        /// 参数设置
        /// </summary>
        /// <param name="fileName">文件名</param>
        public OFDataReader SetParams(string fileName)
        {
            return SetParams(fileName, dict_type);
        }
        /// <summary>
        /// 参数设置
        /// </summary>
        /// <param name="fileName">文件名</param>
        /// <param name="dictType">字典名称</param>
        public OFDataReader SetParams(string fileName, string dictType)
        {
            return SetParams(fileName, dictType, iLineColCount.ToString());
        }
        /// <summary>
        /// 参数设置
        /// </summary>
        /// <param name="fileName">文件名</param>
        /// <param name="dictType">字典名称</param>
        /// <param name="colCount">列所在的行号</param>
        public OFDataReader SetParams(string fileName, string dictType, string colCount)
        {
            return SetParams(fileName, dictType, colCount, "");
        }
        /// <summary>
        /// 参数设置
        /// </summary>
        /// <param name="fileName">文件名</param>
        /// <param name="dictType">字典名称</param>
        /// <param name="colCount">列所在的行号</param>
        /// <param name="paramList">参数</param>
        public OFDataReader SetParams(string fileName, string dictType, string colCount, string paramList)
        {
            Dictionary<string, string> param = DataFuns.SplitStringValue(paramList, ',');
            if (dictType.Length > 0)
                dict_type = dictType;
            if (param.ContainsKey("CODEPAGE"))
                encoding = CommFuns.GetEncoding(param["CODEPAGE"]);
            if (colCount.Length > 0)
                int.TryParse(colCount, out iLineColCount);
            foreach (string key in param.Keys)
            {
                if (key.StartsWith(":"))
                {
                    string col_name = key.Substring(1);
                    string col_val = param[key];
                    if (col_val.StartsWith(":"))
                    {
                        int itmp = 0;
                        if (int.TryParse(col_val.Substring(1), out itmp))
                        {
                            colnames_rowindex.Add(itmp, col_name);
                            col_val = "";
                        }
                    }
                    colnames_ext.Add(col_name, col_val);
                }
            }
            Init(fileName);
            return this;
        }

        private void Init(string fileName)
        {
            this.stream = new StreamReader(fileName, encoding);
            Cols_ext = 0;
            foreach (string key in colnames_ext.Keys)
            {
                columnsByName.Add(key, Cols_ext);
                columnsByOrdinal.Add(Cols_ext, key);
                if (colnames_ext[key].Equals("IDENTITY")) Col_rowIndex = Cols_ext;
                Cols_ext++;
            }
            iLineRowCount = iLineColCount;
            int j = 0;
            while (!stream.EndOfStream && (irowIndex < iLineColCount || irowIndex < iLineRowCount))
            {
                string txt = stream.ReadLine();
                irowIndex++;
                if (colnames_rowindex.ContainsKey(irowIndex))
                    colnames_ext[colnames_rowindex[irowIndex]] = txt.Trim();
                else if (irowIndex == iLineColCount)
                {
                    colnames = new DictColInfo[int.Parse(txt.Trim())];//字段数
                    iLineRowCount = iLineColCount + colnames.Length + 1;
                }
                else if (irowIndex > iLineColCount && irowIndex < iLineRowCount)
                {
                    colnames[j] = GetRowDict(dict_type, txt.Trim());//列名
                    columnsByName.Add(colnames[j].COL_NAME, j + Cols_ext);
                    columnsByOrdinal.Add(j + Cols_ext, colnames[j].COL_NAME);
                    j++;
                }
                else if (irowIndex == iLineRowCount)
                {
                    rowcount = int.Parse(txt.Trim());//记录数
                }
            }
            _isClosed = false;
        }

        public bool Read()
        {
            if (stream == null) return false;
            else if (stream.EndOfStream) return false;
            else if (irowIndex >= iLineRowCount + rowcount) return false;
            currentRow = new string[colnames.Length];
            int ibegin = 0;
            string txt = stream.ReadLine();
            irowIndex++;
            byte[] subbyte = encoding.GetBytes(txt);
            for (int j = 0; j < colnames.Length; j++)
            {
                string val = encoding.GetString(subbyte, ibegin, colnames[j].COL_LENGTH).Trim();
                ibegin += colnames[j].COL_LENGTH;
                if (colnames[j].COL_PRECISION > 0 && val.Length > 0)
                {
                    double dtmp = 0;
                    if (double.TryParse(val, out dtmp))
                        val = (dtmp / Math.Pow(10, colnames[j].COL_PRECISION)).ToString();
                    else
                        throw new Exception(val + "不是有效的数值串");
                }
                currentRow[j] = val;
            }
            if (currentRow.Length == 1 && currentRow[0].Length == 0)
                return false;
            return true;
        }
        private struct DictColInfo
        {
            public string COL_NAME;
            public string COL_TYPE;
            public int COL_LENGTH;
            public int COL_PRECISION;
        }
        private DictColInfo GetRowDict(string dict_type, string colname)
        {
            DataRow[] drs = TableDictCache.Select("DICT_TYPE='" + dict_type + "' AND COL_NAME='" + colname + "'");
            if (drs.Length == 0)
                drs = TableDictCache.Select("COL_NAME='" + colname + "'");
            if (drs.Length == 0)
                throw new Exception("找不到列" + colname + "的定义信息");
            DictColInfo dci = new DictColInfo();
            dci.COL_NAME = colname;
            dci.COL_TYPE = drs[0]["COL_TYPE"].ToString();
            string COL_LENGTH = drs[0]["COL_LENGTH"].ToString();
            if (!int.TryParse(COL_LENGTH, out dci.COL_LENGTH))
                dci.COL_LENGTH = int.MaxValue;
            string COL_PRECISION = drs[0]["COL_PRECISION"].ToString();
            if (!int.TryParse(COL_PRECISION, out dci.COL_PRECISION))
                dci.COL_PRECISION = 0;
            return dci;
        }

        /// <summary>
        /// 关闭StreamReader对象和基础流
        /// </summary>
        public void Close()
        {
            if (stream != null) stream.Close();
            _isClosed = true;
        }

        public int FieldCount
        {
            get { return columnsByName.Count; }
        }
        public string GetString(int i)
        {
            if (i == Col_rowIndex)
                return (irowIndex - iLineRowCount).ToString();
            else if (i < Cols_ext)
                return colnames_ext[columnsByOrdinal[i]];
            else
                return currentRow[i - Cols_ext];
        }

        public object GetValue(int i)
        {
            if (i == Col_rowIndex)
                return irowIndex - iLineRowCount;
            else if (i < Cols_ext)
                return colnames_ext[columnsByOrdinal[i]];
            else
            {
                if (currentRow[i - Cols_ext].Length > 0)
                    return currentRow[i - Cols_ext];
                else
                    return DBNull.Value;
            }
        }

        public string GetName(int i)
        {
            return columnsByOrdinal[i];
        }

        public int GetOrdinal(string name)
        {
            return columnsByName[name];
        }

        public int Depth
        {
            get
            {
                return 0;
            }
        }

        public bool IsClosed
        {
            get
            {
                return _isClosed;
            }
        }

        public int RecordsAffected
        {
            get
            {
                return -1;
            }
        }

        public DataTable GetSchemaTable()
        {
            DataTable dt = new DataTable();
            dt.Columns.Add("ColumnName", typeof(string));
            dt.Columns.Add("ColumnOrdinal", typeof(int));
            dt.Columns.Add("ColumnSize", typeof(int)).DefaultValue = 255;
            dt.Columns.Add("NumericPrecision", typeof(short)).DefaultValue = 255;
            dt.Columns.Add("NumericScale", typeof(short)).DefaultValue = 255;
            dt.Columns.Add("IsUnique", typeof(bool)).DefaultValue = false;
            dt.Columns.Add("IsKey", typeof(bool));
            dt.Columns.Add("BaseServerName", typeof(string));
            dt.Columns.Add("BaseCatalogName", typeof(string));
            dt.Columns.Add("BaseColumnName", typeof(string));
            dt.Columns.Add("BaseSchemaName", typeof(string));
            dt.Columns.Add("BaseTableName", typeof(string));
            dt.Columns.Add("DataType", typeof(System.Type));
            dt.Columns.Add("AllowDBNull", typeof(bool)).DefaultValue = false;
            dt.Columns.Add("ProviderType", typeof(int)).DefaultValue = 22;
            dt.Columns.Add("IsAliased", typeof(bool));
            dt.Columns.Add("IsExpression", typeof(bool));
            dt.Columns.Add("IsIdentity", typeof(bool)).DefaultValue = false;
            dt.Columns.Add("IsAutoIncrement", typeof(bool)).DefaultValue = false;
            dt.Columns.Add("IsRowVersion", typeof(bool)).DefaultValue = false;
            dt.Columns.Add("IsHidden", typeof(bool));
            dt.Columns.Add("IsLong", typeof(bool)).DefaultValue = false;
            dt.Columns.Add("IsReadOnly", typeof(bool)).DefaultValue = false;
            dt.Columns.Add("ProviderSpecificDataType", typeof(System.Type));
            dt.Columns.Add("DataTypeName", typeof(string)).DefaultValue = "string";
            dt.Columns.Add("XmlSchemaCollectionDatabase", typeof(string));
            dt.Columns.Add("XmlSchemaCollectionOwningSchema", typeof(string));
            dt.Columns.Add("XmlSchemaCollectionName", typeof(string));
            dt.Columns.Add("UdtAssemblyQualifiedName", typeof(string)).DefaultValue = 22;
            dt.Columns.Add("NonVersionedProviderType", typeof(int));
            dt.Columns.Add("IsColumnSet", typeof(bool)).DefaultValue = false;
            for (int i = 0; i < FieldCount; i++)
            {
                DataRow dr = dt.NewRow();
                dr["ColumnName"] = GetName(i);
                dr["ColumnOrdinal"] = i;
                dr["BaseColumnName"] = GetName(i);
                dr["DataType"] = GetFieldType(i);
                dr["ProviderSpecificDataType"] = GetFieldType(i);
                dt.Rows.Add(dr);
            }
            return dt;
        }

        public bool NextResult()
        {
            return false;
        }

        public object this[int i]
        {
            get
            {
                return GetValue(i);
            }
        }
        public object this[string name]
        {
            get
            {
                return GetValue(columnsByName[name]);
            }
        }
        public bool GetBoolean(int i)
        {
            return bool.Parse(GetString(i));
        }
        public byte GetByte(int i)
        {
            return byte.Parse(GetString(i));
        }
        public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
        {
            return -1;
        }
        public char GetChar(int i)
        {
            return char.Parse(GetString(i));
        }
        public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)
        {
            return -1;
        }
        public IDataReader GetData(int i)
        {
            return null;
        }
        public string GetDataTypeName(int i)
        {
            return GetFieldType(i).Name;
        }
        public DateTime GetDateTime(int i)
        {
            return DateTime.Parse(GetString(i));
        }
        public decimal GetDecimal(int i)
        {
            return decimal.Parse(GetString(i));
        }
        public double GetDouble(int i)
        {
            return double.Parse(GetString(i));
        }
        public Type GetFieldType(int i)
        {
            return typeof(string);
        }
        public float GetFloat(int i)
        {
            return float.Parse(GetString(i));
        }
        public Guid GetGuid(int i)
        {
            return Guid.Parse(GetString(i));
        }
        public short GetInt16(int i)
        {
            return short.Parse(GetString(i));
        }
        public int GetInt32(int i)
        {
            return int.Parse(GetString(i));
        }
        public long GetInt64(int i)
        {
            return long.Parse(GetString(i));
        }
        public int GetValues(object[] values)
        {
            for (int i = 0; i < columnsByName.Count; i++)
                values[i] = GetValue(i);
            return columnsByName.Count;
        }
        public bool IsDBNull(int i)
        {
            return (GetValue(i) == DBNull.Value);
        }
        public void Dispose()
        {
            try
            {
                GC.Collect();
            }
            catch { }
        }
        ~OFDataReader()
        {
            Dispose();
        }
    }
}
